package com.justech.eat.service.daemons.impl;

import com.justech.common.util.CollectionUtils;
import com.justech.common.util.DateUtil;
import com.justech.eat.entity.AccMonitorLog;
import com.justech.eat.entity.Order;
import com.justech.eat.entity.OrderDetail;
import com.justech.eat.mapper.mysql.LocationAccMonitorLogMapper;
import com.justech.eat.mapper.mysql.OrderDetailAbnormalRecordMapper;
import com.justech.eat.mapper.sqlserver.AccMonitorLogMapper;
import com.justech.eat.model.SettlementResult;
import com.justech.eat.repository.AccMonitorLogRepository;
import com.justech.eat.service.*;
import com.justech.eat.service.daemons.OrderSettler;
import com.justech.eat.service.event.OrderDetailFinalEvent;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;

import java.util.*;

/**
 * @program: eat-service
 * @description:
 * @author: feifei.li
 * @create: 2020-06-15 16:51
 **/
@Component
public class DefaultOrderSettler implements OrderSettler {


    @Autowired
    LocationAccMonitorLogMapper locationAccMonitorLogMapper;

    @Autowired
    AccMonitorLogMapper accMonitorLogMapper;
    @Autowired
    AccMonitorLogRepository accMonitorLogRepository;
    @Autowired
    UserOrientedOrderService userOrientedOrderService;
    @Autowired
    OrderDetailAbnormalRecordMapper orderDetailAbnormalRecordMapper;
    @Autowired
    OrderService orderService;
    @Autowired
    OrderBatchService orderBatchService;
    @Autowired
    OrderDetailService detailService;
    @Autowired
    ApplicationContext applicationContext;
    @Autowired
    DiningRecordSupplier diningRecordSupplier;

    /** 餐厅用餐记录(刷卡机的记录)，以工号和用餐类别为key **/
    private static Map<String, AccMonitorLog> ACC_MONITOR_LOG_MAP = null;

    /** 订餐系统预订记录 **/
    private static List<Order> ORDERS = null;

    /** 订餐系统预订明细记录，以工号和订餐类别为key **/
    private static Map<String, OrderDetail> ORDERED_MAP = null;

    /** 订餐系统订餐主记录，以主记录id为key **/
    private static Map<Long, Order> LONG_ORDER_MAP = null;

    /** 订餐记录和刷卡记录结算后的结果 **/
    private static List<SettlementResult> SETTLEMENT_RESULTS = new ArrayList<>(16);

    /** sincerity:诚信;    stand_sb_up:放鸽子;    overlord_meal:霸王餐 **/
    public static final int stand_sb_up = 2, overlord_meal = 3, sincerity = 1;

    protected String getDate() {
        return DateUtil.dateToShortDate(new Date());
    }

    private void logger(String msg) {
        System.out.println("[INFO] " + DateUtil.now() + "\t" + msg);
    }

    /**
     * 同步刷卡记录
     *
     * @return
     */
    public void getRefreshCardData() {
        logger("开始获取刷卡记录");
        diningRecordSupplier.synchronization(getDate());
        List<AccMonitorLog> parsedAccMonitorLogs = diningRecordSupplier.getDiningRecords(getDate());
        toAccMonitorLogMap(parsedAccMonitorLogs);
        logger("刷卡数据获取完毕");
    }

    /*将集合转换成map，以O(1)的复杂度查询*/
    private void toAccMonitorLogMap(List<AccMonitorLog> accMonitorLogs) {
        ACC_MONITOR_LOG_MAP = new HashMap<>(accMonitorLogs.size());
        for (AccMonitorLog accMonitorLog : accMonitorLogs) {
            ACC_MONITOR_LOG_MAP.put(accMonitorLog.getJobNumber() + "_" + accMonitorLog.getType(), accMonitorLog);
        }
    }

    protected List<Order> getLocationOrder() {
        logger("开始获取报餐记录");
        ORDERS = orderBatchService.getByDate(getDate());
        logger("报餐记录获取结束，并且成功");
        return ORDERS;
    }


    private void getLocationOrderMap() {
        /*清空结算记录*/
        SETTLEMENT_RESULTS = new ArrayList<>(16);
        ORDERED_MAP = new HashMap<>(ORDERS.size() * 4);
        LONG_ORDER_MAP = new HashMap<>(ORDERS.size());
        for (Order order : ORDERS) {
            LONG_ORDER_MAP.put(order.getId(), order);
            List<OrderDetail> details = order.getOrderDetails();
            for (OrderDetail detail : details) {
                String jobNumber = order.getJobNumber();
                if (detail.getResult() == 1) {
                    ORDERED_MAP.put(jobNumber + "_" + detail.getType(), detail);
                }
            }
        }
    }

    /**
     * 正向结算
     * 检查已定记录是否有刷卡记录,没有则视为异常
     */
    public void toSettlement() {
        logger("开始正向对比");
        if (CollectionUtils.has(ORDERS)) {
            for (Order order : ORDERS) {
                String jobNumber = order.getJobNumber();
                List<OrderDetail> orderDetails = order.getOrderDetails();
                for (OrderDetail detail : orderDetails) {
                    String uniqueIdentification = jobNumber + "_" + detail.getType();
                    if (detail.getResult() == 1) {
                        AccMonitorLog accMonitorLog = ACC_MONITOR_LOG_MAP.get(uniqueIdentification);
                        if (accMonitorLog == null) {
                            addResult(order.getJobNumber(), detail.getType(), stand_sb_up);
                        } else {
                            addResult(order.getJobNumber(), detail.getType(), sincerity);
                        }
                    }
                }
            }
        }
        logger("正向对比结束");
    }

    private void addResult(String jobNumber, int type, int result) {
        SETTLEMENT_RESULTS.add(new SettlementResult(getDate(), jobNumber, type, result));
    }

    /**
     * 反向结算
     *
     * @description 将远程的数据对比本地的数据。得出差异
     */
    public void formSettlement() {
        logger("开始反向对比");
        Set<String> strings = ACC_MONITOR_LOG_MAP.keySet();
        for (String string : strings) {
            AccMonitorLog accMonitorLog = ACC_MONITOR_LOG_MAP.get(string);
            OrderDetail detail = ORDERED_MAP.get(string);
            if (detail == null) {
                /*吃了未定,霸王餐*/
                addResult(accMonitorLog.getJobNumber(), accMonitorLog.getType(), overlord_meal);
            }
        }
        System.out.println("反向对比结束");
    }

    private void prepare() {
        /*获取刷卡机数据*/
        this.getRefreshCardData();
        /*获取用户报餐记录*/
        this.getLocationOrder();
        /*订餐记录转换成map，以更高的效率进行数据比对*/
        getLocationOrderMap();
    }


    public void start() {
        logger("结算功能开始计时");
        long s = System.currentTimeMillis();
        /*准备阶段*/
        this.prepare();
        /*开始进行结算*/
        this.toSettlement();
        /*开始进行反结算*/
        this.formSettlement();
        /*提取结算结果*/
        List<SettlementResult> settlementResults = this.SETTLEMENT_RESULTS;
        /*发送处理事件*/
        logger("通知相关服务处理异常数据");
        applicationContext.publishEvent(new OrderDetailFinalEvent(this, settlementResults));
        logger("异常服务处理结束");
        long e = System.currentTimeMillis();
        logger("结算结束。共计耗时:(" + (e - s) / 1000 + ")秒");
    }

    @Override
    public void settle(String date) {
        start();
    }
}
